﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DDD.Core;
using FloatComparer = DDDTest.Helper.FloatComparer;

using Vector2 = DDD.Core.Vector2<float>;
using Vector3 = DDD.Core.Vector3<float>;


namespace DDDTest.Core {
    [TestClass]
    public class TestVector3 {

        [TestMethod]
        public void Test_New1 () {
            var v = new Vector3 ();

            Assert.AreEqual (3, v.ComponentCount);
            Assert.AreEqual (0, v.X);
            Assert.AreEqual (0, v.Y);
            Assert.AreEqual (0, v.Z);
            Assert.AreEqual (0, v[0]);
            Assert.AreEqual (0, v[1]);
            Assert.AreEqual (0, v[2]);
            Assert.AreEqual (false, v.IsNormalized);
        }

        [TestMethod]
        public void Test_New2 () {
            var v = new Vector3 (1, 2, 3);

            Assert.AreEqual (3, v.ComponentCount);
            Assert.AreEqual (1, v.X);
            Assert.AreEqual (2, v.Y);
            Assert.AreEqual (3, v.Z);
            Assert.AreEqual (1, v[0]);
            Assert.AreEqual (2, v[1]);
            Assert.AreEqual (3, v[2]);
            Assert.AreEqual (false, v.IsNormalized);
        }

        [TestMethod]
        public void Test_New3 () {
            var f = new float[] { 1, 2, 3 };
            var v = new Vector3 (f);
            f[0] = f[1] = f[2] = 0;

            Assert.AreEqual (3, v.ComponentCount);
            Assert.AreEqual (1, v.X);
            Assert.AreEqual (2, v.Y);
            Assert.AreEqual (3, v.Z);
            Assert.AreEqual (1, v[0]);
            Assert.AreEqual (2, v[1]);
            Assert.AreEqual (3, v[2]);
            Assert.AreEqual (false, v.IsNormalized);
        }

        [TestMethod]
        public void Test_New4 () {
            var xy = new Vector2 (1, 2);
            var v = new Vector3 (xy, 3);

            Assert.AreEqual (1, v.X);
            Assert.AreEqual (2, v.Y);
            Assert.AreEqual (3, v.Z);
            Assert.AreEqual (1, v[0]);
            Assert.AreEqual (2, v[1]);
            Assert.AreEqual (3, v[2]);
            Assert.AreEqual (false, v.IsNormalized);
        }

        [TestMethod]
        public void Test_New5 () {

            CollectionAssert.AreEqual (new float[] { 0, 1, 0 }, (float[])Vector3.Up);
            CollectionAssert.AreEqual (new float[] { 0, -1, 0 }, (float[])Vector3.Down);
            CollectionAssert.AreEqual (new float[] { 1, 0, 0 }, (float[])Vector3.Right);
            CollectionAssert.AreEqual (new float[] { -1, 0, 0 }, (float[])Vector3.Left);
            CollectionAssert.AreEqual (new float[] { 0, 0, -1 }, (float[])Vector3.Forward);
            CollectionAssert.AreEqual (new float[] { 0, 0, 1 }, (float[])Vector3.Back);
            CollectionAssert.AreEqual (new float[] { 0, 0, 0 }, (float[])Vector3.Zero);
        }


        [TestMethod]
        public void Test_Indexer () {
            var v = new Vector3 ();
            v[0] = 1;
            v[1] = 2;
            v[2] = 3;
            Assert.AreEqual (1, v[0]);
            Assert.AreEqual (2, v[1]);
            Assert.AreEqual (3, v[2]);
        }

        [TestMethod]
        public void Test_Convertor () {
            var v = new Vector3 (1, 2, 3);
            var ar = new float[] { 1, 2, 3 };

            CollectionAssert.AreEqual (ar, (float[])v);
        }

        [TestMethod]
        public void Test_Operator () {
            var v1 = new Vector3 (1, 2, 3);
            var v2 = new Vector3 (2, 4, 6);
            var v3 = v1 + v2;
            var v4 = v1 - v2;
            var v5 = v1 * 2;
            var v6 = 2 * v1;
            var v7 = v2 / 2;
            var v8 = -v2;

            Assert.AreEqual (3, v3.X);
            Assert.AreEqual (6, v3.Y);
            Assert.AreEqual (9, v3.Z);
            Assert.AreEqual (-1, v4.X);
            Assert.AreEqual (-2, v4.Y);
            Assert.AreEqual (-3, v4.Z);
            Assert.AreEqual (2, v5.X);
            Assert.AreEqual (4, v5.Y);
            Assert.AreEqual (6, v5.Z);
            Assert.AreEqual (2, v6.X);
            Assert.AreEqual (4, v6.Y);
            Assert.AreEqual (6, v6.Z);
            Assert.AreEqual (1, v7.X);
            Assert.AreEqual (2, v7.Y);
            Assert.AreEqual (3, v7.Z);
            Assert.AreEqual (-2, v8.X);
            Assert.AreEqual (-4, v8.Y);
            Assert.AreEqual (-6, v8.Z);
        }

        [TestMethod]
        public void Test_Dot () {
            var a = new Vector3 (1, 2, 3);
            var b = new Vector3 (2, 1, -1);
            var dot = Vector3.Dot (a, b);

            Assert.AreEqual (1, dot, 0.0001);
        }

        [TestMethod]
        public void Test_Cross () {
            var a = new Vector3 (1, 2, 3);
            var b = new Vector3 (2, 1, -1);
            var cross = Vector3.Cross (a, b);

            Assert.AreEqual (-5, cross.X, 0.0001);
            Assert.AreEqual (7, cross.Y, 0.0001);
            Assert.AreEqual (-3, cross.Z, 0.0001);
        }

        [TestMethod]
        public void Test_Length () {
            var v = new Vector3 (1, 2, -2);

            Assert.AreEqual (3, v.Length);
            Assert.AreEqual (9, v.Length2);
        }

        [TestMethod]
        public void Test_Normalize () {
            var v1 = new Vector3 (2, 0, 0);
            var v2 = new Vector3 (0, -2, 0);
            var v3 = new Vector3 (0, 0, -2);
            var v4 = v1.Normalize ();
            var v5 = v2.Normalize ();
            var v6 = v3.Normalize ();

            Assert.AreEqual (true, v4.IsNormalized);
            Assert.AreEqual (true, v5.IsNormalized);
            Assert.AreEqual (true, v6.IsNormalized);

            Assert.AreEqual (1, v4.Length, 0.0001);
            Assert.AreEqual (1, v5.Length, 0.0001);
            Assert.AreEqual (1, v6.Length, 0.0001);
        }

        [TestMethod]
        public void Test_Equals () {
            var v1 = new Vector3 (0, 0, 1.00f);
            var v2 = new Vector3 (0, 0, 1.02f);
            var tmp = GlobalSettings.Tolerance;

            GlobalSettings.Tolerance = 0.1f;

            Assert.IsTrue (v1 == v2);
            Assert.IsTrue (v1.Equals (v2));
            Assert.IsTrue (v1.Equals ((object)v2));
            Assert.IsFalse (v1 != v2);

            GlobalSettings.Tolerance = 0.01f;

            Assert.IsFalse (v1 == v2);
            Assert.IsFalse (v1.Equals (v2));
            Assert.IsFalse (v1.Equals ((object)v2));
            Assert.IsTrue (v1 != v2);

            GlobalSettings.Tolerance = tmp;


        }


    }
}
